<template>
  <div class="virtual-scroll-box" @scroll="handleScroll">
    <div :style="style">
      <div class="virtual-scroll-item" v-for="(item, index) in contentList">
        <slot name="item" :data="item" :index="index"></slot>
      </div>
    </div>
    <div :style="`height: ${totalHeight}px`"></div>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ComputedRef, ref, watch, nextTick, computed } from 'vue';
const props = defineProps({
  data: {
    type: Array,
    default: () => []
  },
  viewcount: {
    type: Number,
    default: 20
  },
  scrollWrapperStyle: {
    type: Object,
    default: () => ({})
  }
});
const scrollindex = ref(0);
const itemHeight = ref(100);
const horizontalCount = ref(1);
const style = computed(() => {
  return {
    transform: `translateY(${(scrollindex.value / horizontalCount.value) * itemHeight.value}px)`,
    ...props.scrollWrapperStyle
  };
});

//

const totalHeight = computed(() => {
  return ((props.data.length - props.viewcount) / horizontalCount.value) * itemHeight.value;
});

const contentList: ComputedRef<any[]> = computed(() => {
  return props.data.slice(scrollindex.value, scrollindex.value + props.viewcount);
});

let lastTime = new Date().getTime();
const getCount = () => {
  if (new Date().getTime() - lastTime < 400) {
    return horizontalCount.value;
  }
  let count = 1;
  const items = document.querySelectorAll('.virtual-scroll-item');
  if (items.length) {
    const { top, height } = items[0].getBoundingClientRect();
    for (let i = 1; i < items.length; i++) {
      const temp = items[i].getBoundingClientRect();
      if (temp.top === top && temp.height === height) {
        count++;
      } else {
        break;
      }
    }
    return count;
  } else {
    return horizontalCount.value;
  }
};
const handleScroll = e => {
  horizontalCount.value = getCount();
  let { scrollTop } = e.target;
  scrollindex.value = Math.floor(scrollTop / itemHeight.value) * horizontalCount.value;
};

const init = async () => {
  await nextTick();
  const item = document.querySelector('.virtual-scroll-item');
  if (item) {
    itemHeight.value = (item as HTMLElement).offsetHeight ?? 0;
  }
};
watch(
  () => props.data,
  () => {
    init();
  },
  { immediate: true, deep: true }
);
const scrollToIndex = (index: number, optipn: ScrollOptions = { behavior: 'smooth' }) => {
  horizontalCount.value = getCount();
  document.querySelector('.virtual-scroll-box')?.scrollTo({
    top: Math.floor((index - 1) / horizontalCount.value) * itemHeight.value,
    ...optipn
  });
};
defineExpose({ scrollToIndex });
</script>

<style lang="less" scoped>
.virtual-scroll-box {
  height: 100%;
  overflow-y: scroll;
}
</style>
